use std::process::Command;
use std::path::Path;
use std::{io, fmt, env};
use std::time::SystemTime;
use std::fmt::Formatter;

/// cargo clippy 的时候有太多的无关的打印
/// 其中大部分是unused的打印，因为题目很多东西都是没用的，写一个程序进行过滤
/// 需要先保证程序的正确性
///
/// 追加功能　
/// 如果没有输入文件名，默认文件名就是最近修改的文件的文件名

/// 分析
/// 第一行首先是丢弃的
/// 首先每个模块之间是用一个空行隔开的
/// 每个快的第一行是错误的类型 第二行是文件所在的位置
/// 因此这两个需要一起分析。如果是需要的文件，则收集，否则丢弃这个块里面内容
fn analyse_output(output: String, file_name: &str) -> String {
    let mut result = String::default();
    let mut flag;
    let mut iter = output.lines();
    if !output.starts_with("warning") {
        iter.next();
    }
    loop {
        let string_src = iter.next();
        if let Some(line1) = string_src {
            if let Some(line2) = iter.next() {
                if get_file_name(line2) == file_name {
                    result.push_str("\n");
                    result.push_str(line1);
                    result.push_str("\n");
                    result.push_str(line2);
                    flag = true;
                } else {
                    flag = false;
                }
                loop {
                    let next_line = iter.next().unwrap();
                    if next_line == "" {
                        break;
                    }
                    if flag {
                        result.push_str("\n");
                        result.push_str(next_line);
                    }
                }
            } else {
                break;
            }
        } else {
            break;
        }
    }
    result
}

/// 从输入中提取出来文件名
/// 输入的pattern "src/../...rs"
fn get_file_name(input: &str) -> &str {
    let start = input.rfind('/').unwrap();
    let end = input.rfind("rs").unwrap();
    input.get((start + 1)..(end - 1)).unwrap()
}

#[derive(Debug)]
enum CliErr {
    Io(io::Error),
    LastModifyFileIsDir(String),
    InvalidFileName(String),
}

impl fmt::Display for CliErr {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            CliErr::Io(ref err) => write!(f, "IO err: {}", err),
            CliErr::LastModifyFileIsDir(string) => write!(f, "上次修改的文件是个文件夹 {}", string),
            CliErr::InvalidFileName(string) => write!(f, "非法返回 reason {}", string),
        }
    }
}

impl From<io::Error> for CliErr {
    fn from(err: io::Error) -> Self {
        CliErr::Io(err)
    }
}

type FindLastModifyFileError<T> = Result<T, CliErr>;

/// 获取src下的所有文件
fn get_all_file_from_src_dir() -> FindLastModifyFileError<String> {
    let path = Path::new("./src");
    let (last_modify_file_name, _) = get_last_modify_file_name(path)?;

    if let Some(last_modify_file_name) = last_modify_file_name {
        let last_modify_path = Path::new(&last_modify_file_name);
        if last_modify_path.is_dir() {
            let err_msg = "寻找到的最近一次修改是一个文件夹 ".to_string() + &last_modify_file_name;
            return Err(CliErr::LastModifyFileIsDir(err_msg));
        }
        return Ok(last_modify_file_name);
    }
    Err(CliErr::InvalidFileName("找不到上一次修改的文件".to_string()))
}

//impl PartialOrd for Option<SystemTime> {
//    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
//        if let Some(sys_time) = self {
//            if let Some(other_sts_time) = other {
//                return sys_time.partial_cmp(other_sts_time);
//            }
//            return Some(Greater);
//        } else {
//            if let Some(other_sys_time) = other {
//                return Some(Less);
//            }
//        }
//        Some(Equal)
//    }
//}

/// 获取文件夹下最近一次修改的文件名
fn get_last_modify_file_name(dir: &Path) -> io::Result<(Option<String>, Option<SystemTime>)> {
    let mut result_path = None;
    let mut result_time = None;
    for entry in dir.read_dir()? {
        let entry = entry?;
        let meta = entry.metadata()?;
        let (entry_path, entry_time) =
            if meta.is_dir() {
                get_last_modify_file_name(entry.path().as_path())?
            } else {
                (Some(entry.path().to_str().unwrap().to_string()), Some(meta.modified()?))
            };
        if entry_time.gt(&result_time) {
            result_time = entry_time;
            result_path = entry_path;
        }
    }
    Ok((result_path, result_time))
}


//fn read_from_stdin(buf: &mut String) -> io::Result<()> {
//    (io::stdin().read_line(buf))?;
//    Ok(())
//}


/// 获取系统输入
pub fn filter_irrelevant_clippy_output() {
    let output = Command::new("/usr/bin/cargo").arg("clippy").output().expect("命令 cargo clippy 执行出错");
    let string = String::from_utf8_lossy(&output.stderr).to_string();
    let mut args = env::args();
    args.next();
    let file_name =
        if let Some(arg) = args.next() {
            arg
        } else {
            get_file_name(&get_all_file_from_src_dir().expect("获取最近一次修改的文件名失败")).to_string()
        };

    println!("分析的文件名 {}", file_name);
    let result = analyse_output(string, &file_name);
    println!("分析如下==================");
    println!("{}", result);
}
